package tech.lq0.dreamaticvoyage.client.render.hud;

import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.RenderGuiEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import tech.lq0.dreamaticvoyage.Utils;
import tech.lq0.dreamaticvoyage.init.ItemRegistry;
import tech.lq0.dreamaticvoyage.item.misc.ChaosChecker;
import tech.lq0.dreamaticvoyage.tools.RenderTool;

@Mod.EventBusSubscriber(value = Dist.CLIENT)
public class ChaosRenderer {

    private static final ResourceLocation HUD = Utils.loc("textures/gui/chaos_value.png");
    private static final ResourceLocation BAR = Utils.loc("textures/gui/chaos_value_bar.png");
    private static int lastStatus = 0;
    private static long lastChangeTime = 0;
    private static float lastX = 0;
    private static float lastY = 0;
    private static float lastW = 0;
    private static float lastH = 0;
    private static float lastAlpha = 0;
    private static boolean is0to1 = false;

    private static int lastChaos = 0;
    private static long lastChaosChangeTime = 0;
    private static boolean chaosAnimateFinished = true;

    @SubscribeEvent(priority = EventPriority.NORMAL)
    public static void onRenderGui(RenderGuiEvent.Pre event) {
        var player = Minecraft.getInstance().player;
        if (player == null || player.isSpectator()) return;

        var mainHandItem = player.getMainHandItem();
        var offHandItem = player.getOffhandItem();

        if (!mainHandItem.is(ItemRegistry.CHAOS_CHECKER.get()) && offHandItem.is(ItemRegistry.CHAOS_CHECKER.get())) {
            mainHandItem = offHandItem;
        }

        int status;
        var inventory = player.getInventory();

        if (mainHandItem.is(ItemRegistry.CHAOS_CHECKER.get())) {
            status = 2;
        } else if (inventory.hasAnyMatching(itemStack -> itemStack.is(ItemRegistry.CHAOS_CHECKER.get()))) {
            status = 1;

            mainHandItem = inventory.items.stream().filter(itemStack -> itemStack.is(ItemRegistry.CHAOS_CHECKER.get())).findFirst().orElse(null);
            if (mainHandItem == null) return;
        } else {
            return;
        }

        int chaos = ChaosChecker.getChaos(mainHandItem);
        var minecraft = Minecraft.getInstance();

        float width = event.getWindow().getGuiScaledWidth() / 2f;
        float height = event.getWindow().getGuiScaledHeight() / 2f;

        long MAX_PROGRESS = 300;   // 动画持续时间，单位：毫秒
        float progress = System.currentTimeMillis() - lastChangeTime;

        float alpha;
        if (status == 1) {
            alpha = 0.5f;
        } else {
            alpha = 1;
        }
        if (status != lastStatus) {
            progress = 0;
            if (lastStatus != 2) {
                lastW = 100;
                lastH = 16;
                lastX = width - 50;
                lastY = 0;
                lastAlpha = lastStatus == 1 ? 0.5f : 0;
            } else {
                lastW = 200;
                lastH = 32;
                lastX = width - 101;
                lastY = height + 10;
                lastAlpha = 1;
            }
            is0to1 = lastStatus == 0 && status == 1;
            lastStatus = status;
            lastChangeTime = System.currentTimeMillis();
        }

        float rate = (float) Math.min(1, Math.sqrt(Math.sqrt(progress / MAX_PROGRESS)));

        // 设置透明度
        // TODO 修复透明度无效的Bug
        RenderSystem.disableDepthTest();
        RenderSystem.depthMask(false);
        RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA,
                GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO);
        RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, ease(lastAlpha, alpha, rate));
        RenderSystem.disableDepthTest();

        var gui = event.getGuiGraphics();

        // 渲染外框
        minecraft.getTextureManager().bindForSetup(HUD);
        if (status == 2) {
            RenderTool.preciseBlit(gui, HUD, ease(lastX, width - 101, rate), ease(lastY, height + 10, rate), ease(lastW, 200, rate), ease(lastH, 32, rate), -0.5f, 0, 200, 32, 200, 32);
        } else {
            RenderTool.preciseBlit(gui, HUD, ease(lastX, width - 50, rate), ease(lastY, 0, rate), ease(lastW, 100, rate), ease(lastH, 16, rate), -0.5f, 0, 200, 32, 200, 32);
        }

        // 渲染条
        minecraft.getTextureManager().bindForSetup(BAR);
        if (is0to1) {
            rate = 1;
        }

        if (chaosAnimateFinished && chaos != lastChaos) {
            lastChaosChangeTime = System.currentTimeMillis();
            chaosAnimateFinished = false;
        }
        float msPassed = System.currentTimeMillis() - lastChaosChangeTime;
        float chaosRate = (float) Math.min(1, Math.sqrt(Math.sqrt(msPassed / MAX_PROGRESS)));

        // 动画播放过程中的临时混沌值
        float tempChaos = ease((float) lastChaos, chaos, chaosRate);
        final float start = width - 33 + 30 - 30 * tempChaos / 100f;
        final float end = width - 66 + 60 - 60 * tempChaos / 100f;

        if (status == 2) {
            // 转换到屏幕中间显示
            if (tempChaos > 0) {
                // 混沌
                RenderTool.preciseBlit(gui, BAR, ease(start, end, rate),
                        ease(6, height + 23, rate),
                        ease(30 * tempChaos / 100f, 60 * tempChaos / 100f, rate),
                        ease(4, 6, rate),
                        ease(60 - (60 * tempChaos / 100f), 0.5f + 60 - (60 * tempChaos / 100f), rate),
                        1,
                        60 * tempChaos / 100f, 6, 60, 15);
            } else if (tempChaos < 0) {
                // 清楚
                RenderTool.preciseBlit(gui, BAR, width + ease(3, 6, rate),
                        ease(6, height + 23, rate),
                        ease(30 * tempChaos / -100f, 60 * tempChaos / -100f, rate),
                        ease(4, 6, rate),
                        0.5f,
                        8,
                        60 * tempChaos / -100f, 6, 60, 15);
            }
            var font = minecraft.font;
            String text = String.format("%.1f", Math.abs(tempChaos));
            float tempRate = (tempChaos + 100) / 200f;
            font.drawInBatch(
                    text,
                    width - font.width(text) / 2f,
                    height + 36,
                    0xFF << 16 | ease(0xF9, 0xD0, tempRate) << 8 | ease(0xE1, 0xE5, tempRate),
                    true,
                    event.getGuiGraphics().pose().last().pose(),
                    event.getGuiGraphics().bufferSource(),
                    Font.DisplayMode.NORMAL,
                    0,
                    0xF000F0
            );
        } else {
            // 转换到屏幕顶端显示/消失
            if (tempChaos > 0) {
                // 混沌
                RenderTool.preciseBlit(gui, BAR, ease(end, start + 0.5f, rate),
                        ease(height + 23, 6.5f, rate),
                        ease(60 * tempChaos / 100f, 30 * tempChaos / 100f, rate),
                        ease(6, 3, rate),
                        ease(0.5f + 60 - (60 * tempChaos / 100f), 60 - (60 * tempChaos / 100f), rate),
                        1,
                        60 * tempChaos / 100f, 6, 60, 15);
            } else if (tempChaos < 0) {
                // 清楚
                RenderTool.preciseBlit(gui, BAR, width + ease(6, 4, rate),
                        ease(height + 23, 6.5f, rate),
                        ease(60 * tempChaos / -100f, 30 * tempChaos / -100f, rate),
                        ease(6, 3, rate),
                        1,
                        8,
                        60 * tempChaos / -100f, 6, 60, 15);
            }
        }

        if (msPassed >= MAX_PROGRESS) {
            if (!chaosAnimateFinished) {
                lastChaos = chaos;
            }
            chaosAnimateFinished = true;
        }

        // 还原透明度
        RenderSystem.depthMask(true);
        RenderSystem.enableDepthTest();
//        RenderSystem.enableAlphaTest();
        RenderSystem.clearColor(1.0F, 1.0F, 1.0F, 1.0F);

    }

    private static float ease(float start, float end, float rate) {
        return start + (end - start) * rate;
    }

    private static int ease(int start, int end, float rate) {
        return (int) (start + (end - start) * rate);
    }
}
